<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>发票数据展示 - 列表/卡片视图切换</title>
    <!-- 引入Font Awesome -->
    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <style>
        /* 基础样式 */
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
        }

        body {
            background-color: #f8f9fa;
            color: #343a40;
            line-height: 1.6;
        }

        .container {
            max-width: 1200px;
            margin: 0 auto;
            padding: 2rem 1rem;
        }

        header {
            margin-bottom: 2rem;
        }

        h1 {
            font-size: 2rem;
            color: #2c3e50;
            margin-bottom: 0.5rem;
        }

        .header-desc {
            color: #6c757d;
            font-size: 1.05rem;
        }

        /* 控制栏样式 */
        .controls {
            display: flex;
            flex-wrap: wrap;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 1.5rem;
            gap: 1rem;
        }

        .view-controls {
            display: flex;
            background-color: #fff;
            border-radius: 6px;
            box-shadow: 0 1px 3px rgba(0,0,0,0.1);
            overflow: hidden;
        }

        .view-btn {
            padding: 0.6rem 1.2rem;
            border: none;
            background: none;
            cursor: pointer;
            display: flex;
            align-items: center;
            gap: 0.5rem;
            font-size: 0.9rem;
            transition: all 0.3s ease;
        }

        .view-btn.active {
            background-color: #28a745;
            color: white;
        }

        .view-btn:not(.active):hover {
            background-color: #f1f3f5;
        }

        .action-btn {
            padding: 0.6rem 1.2rem;
            border-radius: 6px;
            border: none;
            background-color: #28a745;
            color: white;
            font-weight: 500;
            cursor: pointer;
            display: flex;
            align-items: center;
            gap: 0.5rem;
            transition: background-color 0.3s ease;
        }

        .action-btn:hover {
            background-color: #218838;
        }

        /* 加载状态 */
        .loading {
            padding: 4rem 0;
            text-align: center;
            display: none;
        }

        .spinner {
            display: inline-block;
            width: 3rem;
            height: 3rem;
            border: 3px solid rgba(40, 167, 69, 0.3);
            border-radius: 50%;
            border-top-color: #28a745;
            animation: spin 1s ease-in-out infinite;
        }

        @keyframes spin {
            to { transform: rotate(360deg); }
        }

        .loading-text {
            margin-top: 1rem;
            color: #6c757d;
        }

        /* 错误提示 */
        .error {
            background-color: #f8d7da;
            border-left: 4px solid #dc3545;
            border-radius: 4px;
            padding: 1rem;
            margin-bottom: 1.5rem;
            display: none;
        }

        .error-content {
            display: flex;
            align-items: flex-start;
            gap: 0.75rem;
        }

        .error-icon {
            color: #dc3545;
            margin-top: 0.25rem;
        }

        .error-title {
            font-weight: 600;
            color: #721c24;
            margin-bottom: 0.25rem;
        }

        .error-message {
            color: #721c24;
            font-size: 0.9rem;
        }

        /* 空状态 */
        .empty-state {
            background-color: white;
            border-radius: 6px;
            padding: 3rem;
            text-align: center;
            box-shadow: 0 1px 3px rgba(0,0,0,0.1);
            display: none;
        }

        .empty-icon {
            font-size: 5rem;
            color: #adb5bd;
            margin-bottom: 1rem;
        }

        .empty-title {
            font-size: 1.2rem;
            font-weight: 600;
            color: #2c3e50;
            margin-bottom: 0.5rem;
        }

        .empty-desc {
            color: #6c757d;
        }

        /* 列表视图样式 */
        .list-view {
            background-color: white;
            border-radius: 6px;
            box-shadow: 0 1px 3px rgba(0,0,0,0.1);
            overflow: hidden;
            display: none;
        }

        .data-table {
            width: 100%;
            border-collapse: collapse;
        }

        .table-header {
            background-color: #f8f9fa;
        }

        .table-header th {
            padding: 1rem;
            text-align: left;
            font-size: 0.85rem;
            font-weight: 600;
            color: #6c757d;
            text-transform: uppercase;
            letter-spacing: 0.5px;
            border-bottom: 1px solid #dee2e6;
        }

        .table-body tr {
            border-bottom: 1px solid #e9ecef;
            transition: background-color 0.2s ease;
        }

        .table-body tr:hover {
            background-color: #f8f9fa;
        }

        .table-body td {
            padding: 1rem;
            font-size: 0.9rem;
            color: #343a40;
        }

        .file-icon {
            color: #6c757d;
            font-size: 1.5rem;
        }

        .badge {
            padding: 0.25rem 0.75rem;
            border-radius: 999px;
            font-size: 0.75rem;
            font-weight: 600;
        }

        .badge-authentic {
            background-color: #d4edda;
            color: #155724;
        }

        .badge-not-authentic {
            background-color: #f8d7da;
            color: #721c24;
        }

        .text-muted {
            color: #6c757d;
            font-size: 0.85rem;
        }

        /* 卡片视图样式 */
        .card-view {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
            gap: 1.5rem;
            margin-bottom: 2rem;
            display: none;
        }

        .invoice-card {
            background-color: white;
            border-radius: 8px;
            overflow: hidden;
            box-shadow: 0 2px 8px rgba(0,0,0,0.08);
            transition: transform 0.3s ease, box-shadow 0.3s ease;
        }

        .invoice-card:hover {
            transform: translateY(-5px);
            box-shadow: 0 8px 16px rgba(0,0,0,0.12);
        }

        .card-header {
            padding: 1.2rem;
            background-color: #f8f9fa;
            border-bottom: 1px solid #e9ecef;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .card-type {
            font-weight: 600;
            color: #2c3e50;
        }

        .card-body {
            padding: 1.2rem;
        }

        .invoice-number {
            font-family: monospace;
            word-break: break-all;
            font-size: 0.9rem;
            margin-bottom: 1rem;
            padding: 0.5rem;
            background-color: #f8f9fa;
            border-radius: 4px;
        }

        .info-item {
            display: flex;
            justify-content: space-between;
            margin-bottom: 0.8rem;
            font-size: 0.9rem;
        }

        .info-label {
            color: #6c757d;
        }

        .card-footer {
            padding: 1.2rem;
            border-top: 1px solid #e9ecef;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .file-info {
            display: flex;
            align-items: center;
            gap: 0.5rem;
            font-size: 0.85rem;
            color: #6c757d;
        }

        .file-icon-card {
            font-size: 1.2rem;
        }

        /* 动画效果 */
        @keyframes fadeIn {
            from { opacity: 0; transform: translateY(10px); }
            to { opacity: 1; transform: translateY(0); }
        }

        .fade-in {
            animation: fadeIn 0.5s ease forwards;
        }

        .invoice-card {
            opacity: 0;
        }

        /* 响应式设计 */
        @media (max-width: 768px) {
            .controls {
                flex-direction: column;
                align-items: stretch;
            }

            .view-controls {
                width: 100%;
            }

            .view-btn {
                flex: 1;
                justify-content: center;
            }

            .list-view {
                overflow-x: auto;
            }

            .data-table {
                min-width: 768px;
            }
        }
    </style>
</head>
<body>
<div class="container">
    <header>
        <h1>发票数据展示</h1>
        <p class="header-desc">支持列表视图和卡片视图切换，数据格式严格遵循指定接口规范</p>
    </header>

    <div class="controls">
        <div class="view-controls">
            <button id="listViewBtn" class="view-btn active">
                <i class="fa fa-list"></i>列表视图
            </button>
            <button id="cardViewBtn" class="view-btn">
                <i class="fa fa-th-large"></i>卡片视图
            </button>
        </div>
        <button id="loadDataBtn" class="action-btn">
            <i class="fa fa-refresh"></i>加载发票数据
        </button>
    </div>

    <!-- 加载状态 -->
    <div id="loading" class="loading">
        <div class="spinner"></div>
        <p class="loading-text">正在加载发票数据，请稍候...</p>
    </div>

    <!-- 错误提示 -->
    <div id="error" class="error">
        <div class="error-content">
            <i class="fa fa-exclamation-circle error-icon fa-lg"></i>
            <div>
                <h3 class="error-title" id="errorTitle">加载失败</h3>
                <p class="error-message" id="errorMessage">无法加载发票数据，请稍后重试</p>
            </div>
        </div>
    </div>

    <!-- 列表视图容器 -->
    <div id="listView" class="list-view">
        <table class="data-table">
            <thead class="table-header">
            <tr>
                <th>发票编号</th>
                <th>类型</th>
                <th>文件类型</th>
                <th>上传时间</th>
                <th>识别时间</th>
                <th>真实性</th>
            </tr>
            </thead>
            <tbody id="listBody" class="table-body">
            <!-- 列表内容将通过JavaScript动态生成 -->
            </tbody>
        </table>
    </div>

    <!-- 卡片视图容器 -->
    <div id="cardView" class="card-view">
        <!-- 卡片内容将通过JavaScript动态生成 -->
    </div>

    <!-- 空状态 -->
    <div id="emptyState" class="empty-state">
        <i class="fa fa-file-pdf-o empty-icon"></i>
        <h3 class="empty-title">暂无发票数据</h3>
        <p class="empty-desc">点击"加载发票数据"按钮获取发票信息</p>
    </div>
</div>

<script>
    // DOM元素引用
    const loadDataBtn = document.getElementById('loadDataBtn');
    const listViewBtn = document.getElementById('listViewBtn');
    const cardViewBtn = document.getElementById('cardViewBtn');
    const listView = document.getElementById('listView');
    const cardView = document.getElementById('cardView');
    const listBody = document.getElementById('listBody');
    const loading = document.getElementById('loading');
    const error = document.getElementById('error');
    const errorTitle = document.getElementById('errorTitle');
    const errorMessage = document.getElementById('errorMessage');
    const emptyState = document.getElementById('emptyState');
    const API_URL = 'http://localhost:8080/api/invoices/';
    // 当前视图模式，默认为列表视图
    let currentView = 'list';

    // 存储发票数据
    let invoiceData = [];

    // 绑定事件监听器
    loadDataBtn.addEventListener('click', loadInvoiceData);
    listViewBtn.addEventListener('click', () => switchView('list'));
    cardViewBtn.addEventListener('click', () => switchView('card'));

    // 生成模拟数据 - 严格遵循指定的接口返回格式
    function generateMockData() {
        // 发票类型
        const invoiceTypes = ['增值税专用发票', '增值税普通发票'];

        // 生成随机日期
        function randomDate() {
            const start = new Date(2025, 0, 1);
            const end = new Date();
            const randomDate = new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime()));
            return randomDate.toISOString().replace('Z', '').split('.')[0];
        }

        // 生成随机发票编号
        function generateInvoiceNumber() {
            const prefix = '25617000000';
            const suffix = Math.floor(Math.random() * 1000000000000).toString().padStart(12, '0');
            return prefix + suffix;
        }

        // 生成随机文件路径
        function generateFilePath(id) {
            const extensions = ['pdf', 'PDF', 'jpg', 'JPG', 'png', 'PNG'];
            const ext = extensions[Math.floor(Math.random() * extensions.length)];
            const fileName = `${Math.random().toString(36).substring(2, 15)}-${id}.${ext.toLowerCase()}`;
            return `./uploads\\${fileName}`;
        }

        // 生成发票数据
        const invoices = [];
        const count = Math.floor(Math.random() * 5) + 5; // 5-10条数据

        for (let i = 1; i <= count; i++) {
            const fileType = Math.random() > 0.3 ? 'PDF' :
                Math.random() > 0.5 ? 'JPG' : 'PNG';

            invoices.push({
                id: i,
                invoiceNumber: generateInvoiceNumber(),
                seller: Math.random() > 0.3 ? `卖家${i}有限公司` : null,
                buyer: Math.random() > 0.3 ? `买家${i}有限公司` : null,
                amount: Math.random() > 0.3 ? (Math.random() * 10000).toFixed(2) : null,
                date: Math.random() > 0.3 ? randomDate().split('T')[0] : null,
                type: invoiceTypes[Math.floor(Math.random() * invoiceTypes.length)],
                filePath: generateFilePath(i),
                fileType: fileType,
                uploadTime: randomDate(),
                isAuthentic: Math.random() > 0.2 ? 1 : 0, // 80%概率为真
                recognitionTime: randomDate()
            });
        }

        // 严格遵循指定的接口返回格式
        return {
            "code": 200,
            "message": "success",
            "data": invoices,
            "timestamp": new Date().getTime()
        };
    }

    // 模拟错误数据 - 遵循相同格式
    const mockErrorData = {
        "code": 500,
        "message": "服务器内部错误",
        "data": null,
        "timestamp": new Date().getTime()
    };

    const mock404Data = {
        "code": 404,
        "message": "请求的资源不存在",
        "data": null,
        "timestamp": new Date().getTime()
    };

    // 加载发票数据
    function loadInvoiceData() {
        // 显示加载状态
        showLoading();
        // 调用实际API
        fetch(API_URL)
            .then(response => {
                console.log(response)
                // 检查响应状态
                if (!response.ok) {
                    throw new Error(`HTTP错误，状态码: ${response.status}`);
                }
                return response.json();
            })
            .then(data => {
                // 处理返回的数据
                if (data && data.length > 0) {
                    // 对数据进行处理，添加额外字段
                    usersData = data.map(user => ({
                        ...user,
                        // 随机生成状态
                        status: Math.random() > 0.2 ? '活跃' : '离线',
                        statusClass: Math.random() > 0.2 ? 'badge-active' : 'badge-inactive'
                    }));
                    renderCurrentView();
                } else {
                    showEmptyState();
                }
            })
            .catch(error => {
                // 处理错误
                console.error('API请求错误:', error);
                showError('加载失败', error.message || '无法连接到API服务器，请检查网络');
            });

    }

    // 处理响应数据
    function handleResponse(data) {
        if (data.code === 200 && data.success !== false && data.data && data.data.length > 0) {
            // 成功获取数据，保存并渲染
            invoiceData = data.data;
            renderCurrentView();
        } else if (data.code === 404) {
            // 404错误处理
            showError('资源未找到', data.message || '请求的接口地址不存在 (404)');
        } else if (data.code === 500) {
            // 500错误处理
            showError('服务器错误', data.message || '服务器内部错误，请稍后重试 (500)');
        } else {
            // 空数据或其他错误处理
            if (data.data && data.data.length === 0) {
                showEmptyState();
            } else {
                showError('加载失败', data.message || '获取发票数据失败');
            }
        }
    }

    // 切换视图模式
    function switchView(viewType) {
        if (currentView === viewType) return;

        currentView = viewType;

        // 更新按钮状态
        if (viewType === 'list') {
            listViewBtn.classList.add('active');
            cardViewBtn.classList.remove('active');
        } else {
            cardViewBtn.classList.add('active');
            listViewBtn.classList.remove('active');
        }

        // 如果已有数据，渲染当前视图
        if (invoiceData.length > 0) {
            renderCurrentView();
        }
    }

    // 渲染当前视图
    function renderCurrentView() {
        if (currentView === 'list') {
            renderListView();
        } else {
            renderCardView();
        }
    }

    // 格式化日期显示
    function formatDate(dateString) {
        if (!dateString) return 'N/A';
        // 将类似"2025-08-17T19:14:55"格式转换为"2025-08-17 19:14"
        return dateString.replace('T', ' ').substring(0, 16);
    }

    // 渲染列表视图
    function renderListView() {
        // 清空列表内容
        listBody.innerHTML = '';

        // 遍历发票数据，创建列表行
        invoiceData.forEach((invoice, index) => {
            const row = document.createElement('tr');
            row.className = 'fade-in';
            row.style.animationDelay = `${index * 0.1}s`;

            // 处理真实性显示
            const authenticText = invoice.isAuthentic === 1 ? '真实' : '虚假';
            const authenticClass = invoice.isAuthentic === 1 ? 'badge-authentic' : 'badge-not-authentic';

            row.innerHTML = `
                    <td class="font-mono">${invoice.invoiceNumber}</td>
                    <td>${invoice.type}</td>
                    <td>${invoice.fileType}</td>
                    <td class="text-muted">${formatDate(invoice.uploadTime)}</td>
                    <td class="text-muted">${formatDate(invoice.recognitionTime)}</td>
                    <td><span class="badge ${authenticClass}">${authenticText}</span></td>
                `;

            listBody.appendChild(row);
        });

        // 显示列表视图，隐藏其他状态
        listView.style.display = 'block';
        cardView.style.display = 'none';
        loading.style.display = 'none';
        error.style.display = 'none';
        emptyState.style.display = 'none';
    }

    // 渲染卡片视图
    function renderCardView() {
        // 清空卡片内容
        cardView.innerHTML = '';

        // 遍历发票数据，创建卡片
        invoiceData.forEach((invoice, index) => {
            const card = document.createElement('div');
            card.className = 'invoice-card fade-in';
            card.style.animationDelay = `${index * 0.1}s`;

            // 处理真实性显示
            const authenticText = invoice.isAuthentic === 1 ? '真实' : '虚假';
            const authenticClass = invoice.isAuthentic === 1 ? 'badge-authentic' : 'badge-not-authentic';

            // 处理金额显示
            const amountDisplay = invoice.amount ? `¥${invoice.amount}` : 'N/A';

            // 处理买卖方显示
            const sellerDisplay = invoice.seller || '未提供';
            const buyerDisplay = invoice.buyer || '未提供';

            card.innerHTML = `
                    <div class="card-header">
                        <span class="card-type">${invoice.type}</span>
                        <span class="badge ${authenticClass}">${authenticText}</span>
                    </div>
                    <div class="card-body">
                        <div class="invoice-number">
                            <span class="info-label">发票编号：</span>${invoice.invoiceNumber}
                        </div>
                        <div class="info-item">
                            <span class="info-label">卖方：</span>
                            <span>${sellerDisplay}</span>
                        </div>
                        <div class="info-item">
                            <span class="info-label">买方：</span>
                            <span>${buyerDisplay}</span>
                        </div>
                        <div class="info-item">
                            <span class="info-label">金额：</span>
                            <span>${amountDisplay}</span>
                        </div>
                        <div class="info-item">
                            <span class="info-label">日期：</span>
                            <span>${invoice.date || '未提供'}</span>
                        </div>
                        <div class="info-item">
                            <span class="info-label">上传时间：</span>
                            <span class="text-muted">${formatDate(invoice.uploadTime)}</span>
                        </div>
                    </div>
                    <div class="card-footer">
                        <div class="file-info">
                            <i class="fa fa-file-${invoice.fileType.toLowerCase()}-o file-icon-card"></i>
                            <span>${invoice.fileType}</span>
                        </div>
                        <span class="text-muted text-sm">ID: ${invoice.id}</span>
                    </div>
                `;

            cardView.appendChild(card);

            // 触发动画
            setTimeout(() => {
                card.style.opacity = 1;
            }, 50);
        });

        // 显示卡片视图，隐藏其他状态
        cardView.style.display = 'grid';
        listView.style.display = 'none';
        loading.style.display = 'none';
        error.style.display = 'none';
        emptyState.style.display = 'none';
    }

    // 显示加载状态
    function showLoading() {
        loading.style.display = 'block';
        listView.style.display = 'none';
        cardView.style.display = 'none';
        error.style.display = 'none';
        emptyState.style.display = 'none';
    }

    // 显示错误信息
    function showError(title, message) {
        errorTitle.textContent = title;
        errorMessage.textContent = message;
        error.style.display = 'block';
        loading.style.display = 'none';
        listView.style.display = 'none';
        cardView.style.display = 'none';
        emptyState.style.display = 'none';
    }

    // 显示空状态
    function showEmptyState() {
        emptyState.style.display = 'block';
        loading.style.display = 'none';
        listView.style.display = 'none';
        cardView.style.display = 'none';
        error.style.display = 'none';
    }
</script>
</body>
</html>
